#!/usr/bin/php
<?php
  /*
 * autoDrop - Flood detection and blocking script for apache access log
 * @copyright Kivanc Erten <kivancerten@gmail.com>
 * @author Kivanc Erten <kivancerten@gmail.com>
 * @version 0.2
 * @license GNU GPL v3
 */

$DropDuration	= 100;		//in second, how long ip will be blocked. It should be less than cron frequance.
$DropListPath	= '/root/';	//Script use this path like a database
//$MonitoredFiles			= array('v4/f.php','v4/forward_email.php');
$SendNotificationEmail		= false;
$NotificationEmailAddress	= 'yourmail@.xxx.com';
$Ban24Hour		= true; // To enable 24 Hour ban
$BanLimit		= 4; //how many times ip will be blocked before 24h blocking


function CountIPBan($IP,$BanLimit,$BanCountFile) {

	//echo "CountIPBan: $IP,$BanLimit \n";

	$BanList	= file_get_contents($BanCountFile);
	$NewBanList = '';
	$Return		= true;
	$IPFound	= false;

	if (empty($BanList)) {
		$IPFound = true;
		$NewBanList = $IP."\t1\n";
	}

	$BanList = explode("\n",$BanList);

	if (is_array($BanList) && count($BanList)>0) foreach ($BanList as $BanLine) {

		//echo "{{{ BanLine : $BanLine\n";

		if (empty($BanLine)) continue;

		$BanLineArray = explode("\t",$BanLine);

		if (is_array($BanLineArray) && count($BanLineArray)==2 && $IP == $BanLineArray[0]) {

			$IPFound = true;

			if ($BanLineArray[1]>=$BanLimit) {

				$Return = false;

			} else {

				$NewBanList .= $BanLineArray[0]."\t".(((int)$BanLineArray[1])+1)."\n";
			}

		} else {

			$NewBanList .= $BanLine."\n";
		}

	}

	if ($IPFound==false) {
		$NewBanList .= $IP."\t1\n";
	}

	unlink($BanCountFile);
	file_put_contents($BanCountFile, $NewBanList);

	return $Return;
}

function Add24HBan($IP,$BanList24HFile) {

	$BanList = file_get_contents($BanList24HFile);
	$NewBanList = '';

	if (empty($BanList)) {
		$NewBanList .= $IP."\t".time()."\n";
	}

	$BanList = explode("\n",$BanList);
	if (is_array($BanList)) foreach ($BanList as $BanLine) {

		$BanLineArray = explode("\t",$BanLine);

		if (is_array($BanLineArray) && count($BanLineArray)==2 && $BanLineArray[0]==$IP) {
			$NewBanList .= $IP."\t".time()."\n";
		} else {
			$NewBanList .= $BanLine ."\n";
		}

	}

	unlink($BanList24HFile);
	file_put_contents($BanList24HFile,$NewBanList);
}

function Get24HBanList($BanList24HFile) {

	$BanList = file_get_contents($BanList24HFile);
	$BannedIPs = array();

	$BanList = explode("\n",$BanList);
	if (is_array($BanList)) foreach ($BanList as $BanLine) {
		$BanLineArray = explode("\t",$BanLine);
		if (is_array($BanLineArray) && count($BanLineArray)==2) {
			$BannedIPs[$BanLineArray[0]] = $BanLineArray[1];
		}
	}
	return $BannedIPs;
}

function RemoveIPFrom24HBanList($IP,$BanList24HFile) {

	$BanList = file_get_contents($BanList24HFile);
	$NewBanList = '';

	if (empty($BanList)) {
		return;
	}

	$BanList = explode("\n",$BanList);
	if (is_array($BanList)) foreach ($BanList as $BanLine) {

		$BanLineArray = explode("\t",$BanLine);

		if (!(is_array($BanLineArray) && count($BanLineArray)==2 && $BanLineArray[0]==$IP)) {
			$NewBanList .= $BanLine ."\n";
		}

	}

	unlink($BanList24HFile);
	file_put_contents($BanList24HFile,$NewBanList);
}

$DropListFile 	= $DropListPath.'.autoDropList.txt';
$BanCountFile 	= $DropListPath.'.autoDropBanCounts.txt';
$BanList24HFile = $DropListPath.'.autoDrop24HBanList.txt';
$BanForeverFile = $DropListPath.'.autoDropBanForeverList.txt';
if (!file_exists($DropListFile)) file_put_contents($DropListFile,'');
if (!file_exists($BanCountFile)) file_put_contents($BanCountFile,'');
if (!file_exists($BanList24HFile)) file_put_contents($BanList24HFile,'');
if (!file_exists($BanForeverFile)) file_put_contents($BanForeverFile,'');

$Limit = 25;
if (isset($argv) && isset($argv[1])) {
	$Limit = (float)$argv[1];
}
if ($Limit == 0) $Limit = 25;

$lines = split("\n", file_get_contents("php://stdin", "r"));

$FoundClients = array();
$TotalLineCount = 0;

foreach ($lines as $line) {
	if ($line !== "") {

		$SkipLine = true;

		if (isset($MonitoredFiles) && $MonitoredFiles!==false) foreach ($MonitoredFiles as $EachMonitoredFile) {
			if (strpos($line,$EachMonitoredFile)!==false) {
				$SkipLine = false;
			}
		}

		if (isset($MonitoredFiles) && $MonitoredFiles!==false && $SkipLine) continue;

		$TotalLineCount++;

		$IP = substr($line, 0, strpos($line, ' '));

		if (!isset($FoundClients[$IP])) {

			$FoundClients[$IP] = 1;

		} else {

			$FoundClients[$IP]++;
		}
	}
}



$DroppedIPArray = array();
$DropList = '';

$NotificationText = '';

if (count($FoundClients)) foreach ($FoundClients as $Client => $Count) {


	if ($Count > 40) { // Don't consider when repeat count less then 40

		$Percent = sprintf('%01.2f', (100 * $Count) / $TotalLineCount);

		if ($Percent > $Limit) {

			$DroppedIPArray[] = $Client;
			file_put_contents($DropListFile, $Client . "\t" . time() . "\n", FILE_APPEND);

			$execBlocked = exec("iptables -L -n | grep $Client");

			if (empty($execBlocked)) {

				$execOutput = exec("iptables -I INPUT -s $Client -j DROP");

				echo "CountIPBan() $Client\n";

				if (CountIPBan($Client,$BanLimit,$BanCountFile)==false) { //24H Ban
					if ($Ban24Hour) {
						Add24HBan($Client,$BanList24HFile);
					}
				}

				echo $execOutput;
				echo "Client $Client\t\t$Count [%$Percent] exceeded Limit - BANNED !!! \n";
				$NotificationText .= "Client $Client\t\t$Count [%$Percent] exceeded Limit - BANNED !!! \n";

			}


		} else {
			echo "Client $Client\t\t$Count [%$Percent]\n";
		}
	}

}

if ($SendNotificationEmail && !empty($NotificationText)) {
	mail($NotificationEmailAddress,'autoDrop Notification',$NotificationText);
}

if ($Ban24Hour) {
	$Banned24H_IP_Data = Get24HBanList($BanList24HFile);
	$Banned24HIPs = array_keys($Banned24H_IP_Data);
}

//echo "24Hour bans:".implode(',',$Banned24HIPs);
//Drop List Time Control
if (file_exists($DropListFile)) {

	$DropList = file_get_contents($DropListFile);
	$DropList = explode("\n", $DropList);
	if (is_array($DropList) && count($DropList) > 0) {

		$NewDropList = '';
		$NewDropListArray = array();

		foreach ($DropList as $DropItem) {
			$DropItem = explode("\t", $DropItem);

			if (is_array($DropItem) && count($DropItem) > 0 && !empty($DropItem[0])) {

				$DroppedIP = $DropItem[0];
				$DroppedTime = (int)$DropItem[1];

				$TimeDiff = time() - $DroppedTime;
				if (($TimeDiff > $DropDuration) && (in_array($DroppedIP, $DroppedIPArray) === false)) { // If enough time pass for drop blockage and the IP won't be blocked again


					if (($Ban24Hour==false) || ($Ban24Hour && in_array($DroppedIP,$Banned24HIPs)==false)) { // ip is not in 24H ban list

						$execOutput = exec("iptables -D INPUT -s $DroppedIP -j DROP");
						echo $execOutput;
						echo "$DroppedIP removed from Drop List for duration\n";

					}


				} else if (($TimeDiff > $DropDuration) && (in_array($DroppedIP, $DroppedIPArray) !== false)) { // Enough time pass but IP will be blocked again

					if (in_array($DroppedIP, $NewDropListArray) === false) {

						$NewDropList .= "$DroppedIP\t$DroppedTime\n";
						$NewDropListArray[] = $DroppedIP;

					}

				} else {

					if (in_array($DroppedIP, $NewDropListArray) === false) {

						$NewDropListArray[] = $DroppedIP;
						$NewDropList .= "$DroppedIP\t$DroppedTime\n";

					}
				}
			}
		}

		unlink($DropListFile);
		file_put_contents($DropListFile, $NewDropList);
	}
}


// Check 24H ban, drop

if ($Ban24Hour && is_array($Banned24H_IP_Data)) foreach ($Banned24H_IP_Data as $BannedIP => $BannedTime) {
	if (time() - $BannedTime >= 86400) { //86400 = 24Hour
		exec("iptables -D INPUT -s $BannedIP -j DROP");
		echo "$BanedIP removed from 24 Hour Ban List for duration\n";
		RemoveIPFrom24HBanList($BannedIP,$BanList24HFile);
	}
}

